// vim: fenc=utf8 ff=unix noet ts=4 sts=4 sw=4
// ==UserScript==
// @name           Au counter
// @namespace      http://code.google.com/p/higulo-tools/
// @description    counts your hatsugen
// @include        http://tkido.com/h_jinro/game.php*
// ==/UserScript==

var version = "1.0.4";

// 共通関数 ///////////////////////////////////

// なにもしない。ついでにグローバルを返す
function nop() { return this }

// Firebug コンソールにログ出力
var con = unsafeWindow.console || { log:nop };

// Arrayにコピーして返す。Arrayを渡すとそのまま返す。配列でなければ配列にラップする
Array.from = function (a) {
    if (a instanceof Array) return a;
    if (typeof a.length == "undefined") return [a];
    var r = new Array(a.length);
    for (var i = 0, end = a.length; i < end; i++) r[i] = a[i];
    return r;
}

// イテレータ関数
var $break = function () {}

Array.each = function (a, it) {
    try {
        for (var i = 0, end = a.length; i < end; i++) it(a[i], i, a);
    } catch (e) {
        if (e != $break) throw e;
    }
}

Object.each = function (o, it) {
    try {
        for (var i in o) it(o[i], i, o);
    } catch (e) {
        if (e != $break) throw e;
    }
}

// 圧縮コードを展開する
function decode(it) {
    var cd = "0123456789abcdef"+
             "ghijklmnopqrstuv"+
             "wxyzABCDEFGHIJKL"+
             "MNOPQRSTUVWZYZ_-";
    var y = 0, s = "", flag = false;
    return function (c) {
        var i = cd.indexOf(c);
        if (i >= 0) {
            var cls = Math.floor(i / 16);
            i = i % 16;
            s += cd[i];
            if (cls > 1) flag = true;
            if (cls % 2 == 0) {
                var x = y, z = parseInt("0x"+s);
                y += z;
                if (flag) { it(x, y) } else { it(y) }
                s = "", flag = false;
            }
        }
    }
}

// EUC-JPの１バイト・３バイト文字のマップ
code = "q13231419Ne2Ne2Op8haCh28Aj4Jk3Jhsr7Iisu02176d41433y5b133a9y7CbB6e916h2aada15y6722y8z2C316Dh53y22223A6A62227A7A36z313121412222y32141h35D214A2y23a42eya12B332223413z457D6D314A3y4y6A3A3Ah0z2A4y2A5L519A3313522314412z22216z44453y3B722z5B4B2y3198542z752h85173a542abA2A67C364z94y3a13d1212a6913794c2z23y589y7y35y72B28z816y212342243y3251543F321937y5y531216A2y3237y491d26A7157554J544z6143212z3z5aA2531261edh1D76125Ce1362f4B22z6b2y231444I512131362y474Ah2ay3762z43C7h517315y46z3317z3z3yh921426Fc195dA33G413347J9C32E7h343222E2E225aB334B3f13319G7D4y4774A21931223F451a1532545123B4z21419y61615h03213N33298H26y3cBa14368133I5125y414131e3y616576a3A5ay3Ah043y6F4y73C381a6y45z22243417ah21516y9A214713z9A3c162A22822z313zf12A328536z3A325z4235bD37C3948y41b51312z3h41214F95y26N1dB3C3Nf45A7bC55I7HfG48749a1648a61dz232442A2h2B22153y41cy7A6f239fb71433z2y2Ai3z614y43415N053bz2A48215fK6h13zdB75h1A4Nf74A6B6339E25y8F417A5A41aA43y81745f17765z37186439by5152CaEh0bzh4z3y25yay75z31217276h74y6b314z431224252214z63443531383213231b4y7615B413y7c3A5Aa316y2z31342bC613125596yb7y35321646ad134y24z22351421381643C4D51422143d3341553y4A2z3y481514A8413h52c66A3y217y51414A5323b134yc16J32Eh2Cc274214y2e45A64y2242892473h0zh6yb313415a714h0828161612z3Bh1138A35B4134y4za16143134z32z3641414627ye443632y7A55y61231h016y246D4151582c4B6Fa617y8y8y712y2A3y47ay55z2z4yd1413352442z4K3y3A4z5392164272yb17AfD458z3533384yb361524y27h12D5y44144131713z23z22z4y75142y36B419y722y2Bby327z31494136412154E7493zc1ay75634yh1b72148189626256za12y3212h5y36B21231952355a24zhb5A2814B284515y63z3h0D34z622ye2y252y41449a343y2333183B31415y931612Ahay2337D5948C34y8141d54y9B2B28z293951bz9z2y9212cy45334A8A343161314E593G2b3y3B6a2y664y39y7G4y617z5CaD3z6y6A364D615474354y5374z258143h244A513y281415153a47C736K4B22767J21414bz23y521b4A5B2ay2b1214zh122e47B22424722z42N64z27cy6z833h87z4281cC5a122yh2y8324y54y4175y2123461426Eha45bA3218B24B35y415b8yh06677613284y24123yhc21bA742z9BbA3z3z51h3A42131316Ah1154C32A4C5z6y51692zh04a17543135y6a9zc5E7E36181617y718EeA3N0513zh37D48h69A4AfybC79C315y53C8h175y56815yd12175y371733zhc627yaD3D745418A9y3z4222353C6131355B58d5133az6B91276e1613F4E5154y3145135z6a3C2E6122A2623D218D2L4z8A3z613213K4y3zbz2A2y333N192H873L5654y3z31e14A6J3y2z2D2G4G34z5z315421456B7c419133215734C416225712e28B34b212A362h065y32621853y3z5z2872C223L5213A512B2B2y4ya46518y23d47186N2h0444212657624415334644I2665F3414A4J5A22332E6z3A817C535z41249568A45y424y413DaA4Ac4yaz5yc13N52I4c4c5545A34413z8228y3y41215H4813B41664aH2y4E6225y4B23431b2y772zd15H5712423A37C25524A2235124D46B21254633I21413ya1214913D5y3383622314D3a2z97y421a3323ad1215z7z9db442y2A39A677bA23132314d5521553257312314z5332aDd28213C3B3z21ay55124G31cA7y24B3y4y4B7A9185a26a613y353y424y221393yae4y62y3715D34by216154y4z2182368214F3y451618A93129A6y9293141244B68814y513714124395127A67C6314B635133443y31pdF38318y4B74czb22y5155144z78313561cA4y34z383y8z3y22127z4y6A412z222Ahc4y744c76e2814d1f52C218d1221331458J4A4z5455y92z265916y428a3y5z26y334c4278y51316y4z33714y3A4213c415134Da269z5H6434677y2H4z3A215A3z4222z32217G556224y3y716A6121h02Bay2343z5y36132Ah985D27521312y91231h1y7y6y39b2c2135545y4Ah6ac212z2D2y2A4123631224B4d1298A5y363122514349K5z5A2514Fcy4z2A4B2979A333C274aA224132A455B3267A4z3B313ay516y5F631418B612C6ydD3Cc13z43A53z6y3e5A5H5y54A2I2c13y324z2yh32171243y3155B56A712y2B8b5431az98F4K23A5y349127y47G3H42525A3B52y4D9E2z525223z3z41222314588y5h82y318yh0A2aA3y8398y4ya57y6D46y8B414y23A6z5B5y832325zc43416B5b4z5h8Ad4G33C5z8212192y22513626z3y22B53y41442eC3y335412412682514A43532y72y262d44y6361416b21ez756C55y555a92A2331622517zp9141722242z3y2y6C4F538145z6z8h51b13246A44743F6B695Aka432h13y45E9y65D3A2145B43A2ybz54y294B56BaDay3Ha2y57z317E8y7167235A4D415E5A38y38c5G216y51716y62B214y6z361248C3517j8313yf126215D3212b3146341534244c3dB24138418f25415445c33z25J3b2y2715B46D3z664B28y4I4A2L5123N47442E33675E2z4432y36z5y4y2z35A3ze13214614E6A23I4213D6B6B212C2z3133y271313142F5E29C4526I4D22N423N02z42y924z6B4A7z2312219121h0y7y32z46C32B2A32I2B333H2z9y4D3z2A66z21341h0H24D6y8fC7A42D9A3322B3A21h11v4C644yfy253z8y43272125z613z42j714A652D214h1C9d6712C58543y5y35147h08623ya6298124h1124y592e27B62121843453y32z9cy21413a2A3I312212B3D2Dby33zd3316y33A32C3B29C3z7y31218A42jfz243H33Ah52A393c5194y3y334146H415y5164EjbA7ay3B3y46a151229B4414414y714158F615z2933B2C27kdy213A3y312y3E223y414412y3612413E3K321465y6D3bA9y4N352H4F2146A81234y513A26162715y6y3B44H9425A2y413A74y64A4D3z23A45J24mbc5H96614yh1H215122391b312C5614H4A4C992y3443z44zaz3H2A3231aNb31ldy42B7172z36442Dh1Baa535y2y337A66z22F3F4H212Ec2Fa14A2y5zh2B2173Alvlc_4";
eucbytes = {}
for (var i = 0; i < 128; i++) eucbytes[i] = 1;
eucbytes[0x00a5] = eucbytes[0x203e] = 1;
Array.each(code, decode(function (x, y) {
    if (!y) y = x;
    while (x <= y) eucbytes[x++] = 3;
}));

// 文字列のバイト数を数える
function getByteCount(str, limit) {
    var count = str.length;
    for (var i = 0; count < limit && i < str.length; ++i) {
        var uc = str.charCodeAt(i);
        if (uc == 0x0a) {
            count += 4; // LF = "<br>" なので4バイト
        } else {
            count += eucbytes[uc] || 2;
        }
        count--;
    }
    return count;
}
// 文字列のはじめを比較
String.prototype.startswith = function (n) { return (n.length <= this.length && n == this.substr(0, n.length)) }

// XPath クエリ
function query_xpath (xpath, node) {
    if (!node) node = document;
    var r = document.evaluate(xpath,node,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
    return (r.snapshotLength < 1) ? null : r.snapshotItem(0); // 最初の要素だけを返す
}
// 新しい Element を返す
function build_element (name, attrs, children) {
    var node = document.createElement(name);
    if (attrs) set_attributes(node, attrs);
    if (children) append_children(node, children);
    return node;
}
// Elementに属性・イベントをセット
function set_attributes (node, attrs) {
    Object.each(attrs, function (v, k) {
        if (k == "style") {
            if (typeof v == "string") {
                node.style.cssText = v;
            } else {
                set_attributes(node.style, v);
            }
        } else if (k.startswith("on")) { // on*ではじまるのはイベント
            node.addEventListener(k.substring(2), attrs[k], true);
        } else {
            node[k] = attrs[k];
        }
    });
    return node;
}

// ノードを順次追加
function append_children (node, children) {
    Array.each (children, function (e) {
        var n = (typeof e != "string") ? e : document.createTextNode(e);
        node.appendChild(n);
    });
    return node;
}

// implements /////////////////////////////////

// 正しいページか確認
function validate_page() {
    // ヘッドライン解析
    var headline = query_xpath("//td[@class='headline']");
    if (!headline || !headline.textContent.startswith("◆人狼のなく頃に")) {
        return false;   // インストールしません
    }
    // タイトル解析
    var title = query_xpath("//span[@class='title']");
    if (!title || !title.textContent.match(/～(.+)　(.+)～/)) {
        return false;   // インストールしません
    }
    var place_name = RegExp.$1;
    var log_name   = RegExp.$2;
    if (place_name != "固有結界の中" && log_name != "最新") {
        return false; // インストールしません
    }
    return true;
}

// あぅあぅカウンターを作成して返す
var au_counter = function (text) {
    var coutner, msgdisp;
    var ctrl = build_element("div", { style: "display:inline" }, [
        "現在", counter = build_element("b"), "あぅ　",
        msgdisp = build_element("span", { style: "fontSize:small" }),
    ]);
    var au_data = [
        { limit:700,  msg:"",                               color:"#ffff96" },
        { limit:900,  msg:"それくらいでやめておくのです！", color:"#ffeebb" },
        { limit:1000, msg:"危険なのです！大変なのですよ！", color:"#ffddaa" },
        { limit:1024, msg:"あぅあぅあぅもうだめなのです！", color:"#ffbbaa" },
        { limit:2048, msg:"あうと。切らないと送れないです", color:"#ff9977" },
        {             msg:"あぅあぅあぅ！もう２発言分？！", color:"#ff9977" },
    ];
    var limit_data =
        { limit:2048, msg:"か、数え切れないのです？！（泣", color:"#ff7744" };
    var level = 0;
    // テキストエリアの文字数を数えて、メッセージを更新する
    var update_counter = function () {
        var cnt = getByteCount(this.value, limit_data.limit); // バイト数で数える
        if (cnt > limit_data.limit) { // 数えすぎは無駄なので見切る
            counter.textContent  = "*";
            msgdisp.textContent  = limit_data.msg;
            //this.style.backgroundColor = limit_data.color;
            return;
        }
        counter.textContent = cnt;
        Array.each(au_data, function (au, i) {
            if (!au.limit || cnt < au.limit) {
                if (level == undefined || i != level) {
                    msgdisp.textContent = au.msg;
                    //this.style.backgroundColor = au.color;
                    level = i;
                }
                throw $break;
           }
        });
    }
    update_counter.call(text); // 一度アップデートする（あぅあぅ対策）
    text.addEventListener("keyup", update_counter, true); // イベントの登録
    return ctrl;
}

// main
addEventListener("load", function () {
    if (!validate_page()) return;
    con.log("あぅあぅカウンター " + version + " by mumu.");
    var text = query_xpath("//textarea[@name='TXTMSG']");
    var cell = query_xpath("//textarea[@name='TXTMSG']/../../../tr/td");
    cell.appendChild(au_counter(text));
}, false);

